Argument:
    Positional (value : Expression)
    PositionalUnpack (value : Expression)
    Keyword (name : Identifier, value : Expression)
    KeywordUnpack (value : Expression)

ArgumentList = (items : [Argument])

Parameter = (
    name : Identifier,
    `type` : TypeExpression?,
    value : Expression?
)

ParameterList = (
    positionalOnly : [Parameter],
    positional : [Parameter],
    extraPositional : Parameter?,
    keywordOnly : [Parameter],
    extraKeywords : Parameter?
)

MapKeyValuePair = (
    key : Expression?,
    value : Expression
)

FieldLabelValuePair = (
    label : Identifier,
    value : Expression
)

RelationalOp: one of
    EqualTo NotEqualTo
    LessThan LessEqual GreaterThan GreaterEqual
    Is IsNot In NotIn

RelationalOpValuePair = (
    op : RelationalOp,
    value : Expression
)

ComprehensionFilter = (condition : Expression)

ComprehensionFilterList = (items : [ComprehensionFilter])

Comprehension = (
    isAsync : bool,
    enumerator : Expression,
    enumerable : Expression,
    filters : ComprehensionFilterList
)

ComprehensionList = (items : [Comprehension]+)

Subscript:
    Index (value : Expression)
    Range (lower : Expression?, upper : Expression?, step : Expression?)
    InclusiveRange (lower : Expression, upper : Expression, step : Expression?)
    Extended (dimensions : [Subscript]+)

SubscriptList = (
    items : [Subscript]+,
    hasTrailingComma : bool
)

Expression:
    Null (value : NullLiteral)
    Boolean (value : BooleanLiteral)
    Integer (value : IntegerLiteral)
    Float (value : FloatLiteral)
    Complex (value : ComplexLiteral)
    String (value : StringLiteral)
    ByteString (value : ByteStringLiteral)
    QuoteString (value : StringLiteral)
    QuoteByteString (value : ByteStringLiteral)
    StringSeries (values : [StringLiteral]+)
    ByteStringSeries (values : [ByteStringLiteral]+)
    QuoteStringSeries (values : [StringLiteral]+)
    QuoteByteStringSeries (values : [ByteStringLiteral]+)
    JoinedString (values : [Expression])
    FormattedValue (value : Expression, conversion : char?, format : Expression?)

    NameReference (name : Identifier)
    BuiltinTypeReference (`type` : TypeExpression)
    TypeReference (`type` : TypeExpression)
    SlotValueReference (slot : IntegerLiteral)
    SlotContextReference (slot : IntegerLiteral)
    ResultValueReference
    ResultContextReference
    ThisReference
    BaseReference
    Ellipsis

    Unit
    EmptyList
    EmptySet
    EmptyMap
    Group (operand : Expression)
    
    Tuple (elements : [Expression]+)
    Record (fields : [FieldLabelValuePair]+)
    ValueTuple (elements : [Expression]+)
    ValueRecord (fields : [FieldLabelValuePair]+)

    List (elements : [Expression]+)
    Set (elements : [Expression]+)
    Map (elements : [MapKeyValuePair]+)

    Generator (element : Expression, comprehensions : ComprehensionList)
    ListComprehension (element : Expression, comprehensions : ComprehensionList)
    SetComprehension (element : Expression, comprehensions : ComprehensionList)
    MapComprehension (key : Expression, value : Expression, comprehensions : ComprehensionList)

    Access (operand : Expression, member : Identifier)
    NullableAccess (operand : Expression, member : Identifier)
    Call (operand : Expression, arguments : ArgumentList)
    Subscript (operand : Expression, subscripts : SubscriptList)

    New (`type` : TypeExpression, arguments : ArgumentList)
    Default (`type` : TypeExpression)
    TypeOf (`type` : TypeExpression)
    NameOf (operand : Expression)

    PostfixIncrement (operand : Expression)
    PostfixDecrement (operand : Expression)

    EmptyMutableList
    EmptyMutableSet
    EmptyMutableMap
    
    MutableList (elements : [Expression]+)
    MutableSet (elements : [Expression]+)
    MutableMap (elements : [MapKeyValuePair]+)

    MutableListComprehension (element : Expression, comprehensions : ComprehensionList)
    MutableSetComprehension (element : Expression, comprehensions : ComprehensionList)
    MutableMapComprehension (key : Expression, value : Expression, comprehensions : ComprehensionList)
    
    IsInstanceOf (operand : Expression, `type` : TypeExpression)
    AsInstanceOf (operand : Expression, `type` : TypeExpression)

    Await (operand : Expression)
    Power (left : Expression, right : Expression)
    Positive (operand : Expression)
    Negative (operand : Expression)
    BitwiseNot (operand : Expression)
    LogicalNot (operand : Expression)
    PrefixIncrement (operand : Expression)
    PrefixDecrement (operand : Expression)

    Multiply (left : Expression, right : Expression)
    MatrixMultiply (left : Expression, right : Expression)
    FloorDivide (left : Expression, right : Expression)
    Divide (left : Expression, right : Expression)
    Modulo (left : Expression, right : Expression)

    Add (left : Expression, right : Expression)
    Subtract (left : Expression, right : Expression)

    LeftShift (left : Expression, right : Expression)
    RightShift (left : Expression, right : Expression)
    UnsignedRightShift (left : Expression, right : Expression)
    BitwiseAnd (left : Expression, right : Expression)
    BitwiseXor (left : Expression, right : Expression)
    BitwiseOr (left : Expression, right : Expression)

    Relational (left : Expression, opValuePairs : [RelationalOpValuePair]+)
    
    LogicalAnd (left : Expression, right : Expression)
    LogicalOr (left : Expression, right : Expression)

    Conditional (test : Expression, body : Expression, orElse : Expression)
    Lambda (parameters : ParameterList, body : Expression)
    
    YieldFrom (value : Expression)
    Yield (value : Expression?)
    YieldBreak
    Unpack (operand : Expression)

%%

StringSeries as [StringLiteral]:
    StringLiteral => Sequence.Create($1)
    QuoteStringLiteral => Sequence.Create($1)
    StringSeries StringLiteral => Sequence.Append($1, $2)
    StringSeries QuoteStringLiteral => Sequence.Append($1, $2)

ByteStringSeries as [ByteStringLiteral]:
    ByteStringLiteral => Sequence.Create($1)
    QuoteByteStringLiteral => Sequence.Create($1)
    ByteStringSeries ByteStringLiteral => Sequence.Append($1, $2)
    ByteStringSeries QuoteByteStringLiteral => Sequence.Append($1, $2)

FilterCondition as Expression:
    LogicalOrExpression => $1
    'lambda' LambdaParameterList ':' FilterCondition => Expression.NewLambda($2, $4, @@)

ComprehensionFilter as ComprehensionFilter:
    'if' FilterCondition => ComprehensionFilter.New($2, @@)

ComprehensionFilterList as ComprehensionFilterList:
    ComprehensionFilter* => ComprehensionFilterList.New($1, @1)

Comprehension as Comprehension:
    'for' TargetExpressionList 'in' LogicalOrExpression ComprehensionFilterList => Comprehension.New(False, $2, $4, $5, @@)
    'async' 'for' TargetExpressionList 'in' LogicalOrExpression ComprehensionFilterList => Comprehension.New(True, $3, $5, $6, @@)

ComprehensionList as ComprehensionList:
    Comprehension+ => ComprehensionList.New($1, @1)

Argument as Argument:
    TestExpression => Argument.NewPositional($1, @1)
    '*' TestExpression => Argument.NewPositionalUnpack($2, @@)
    Name '=' TestExpression => Argument.NewKeyword($1, $3, @@)
    '**' TestExpression => Argument.NewKeywordUnpack($2, @@)

ArgumentList as ArgumentList:
    '(' ')' => ArgumentList.New(default([Argument]), @@)
    '(' Argument %+ ',' ','? ')' => ArgumentList.New($2, @@)
    '(' TestExpression ComprehensionList ')' => ArgumentList.New(Sequence.Create(Argument.NewPositional(Expression.NewGenerator($2, $3, @@))), @@)

OptionalArgumentList as ArgumentList:
    => ArgumentList.New(default([Argument]), @@)
    ArgumentList => $1

Subscript as Subscript:
    TestExpression => Subscript.NewIndex($1)
    TestExpression? ':' TestExpression? => Subscript.NewRange($1, $3, None, @@)
    TestExpression? ':' TestExpression? ':' TestExpression? => Subscript.NewRange($1, $3, $5, @@)
    TestExpression '..' TestExpression => Subscript.NewInclusiveRange($1, $3, None, @@)
    TestExpression '..' TestExpression '..' TestExpression => Subscript.NewInclusiveRange($1, $3, $5, @@)

SubscriptList as SubscriptList:
    '[' Subscript %+ ',' ']' => SubscriptList.New($2, False, @@)
    '[' Subscript %+ ',' ',' ']' => SubscriptList.New($2, True, @@)

PrimaryExpression as Expression:
    NullLiteral => Expression.NewNull($1, @1)
    BooleanLiteral => Expression.NewBoolean($1, @1)
    IntegerLiteral => Expression.NewInteger($1, @1)
    FloatLiteral => Expression.NewFloat($1, @1)
    ComplexLiteral => Expression.NewComplex($1, @1)
    StringLiteral => Expression.NewString($1, @1)
    StringLiteral StringSeries => Expression.NewStringSeries(Sequence.Prepend($1, $2), @@)
    QuoteStringLiteral => Expression.NewQuoteString($1, @1)
    QuoteStringLiteral StringSeries => Expression.NewQuoteStringSeries(Sequence.Prepend($1, $2), @@)
    ByteStringLiteral => Expression.NewByteString($1, @1)
    ByteStringLiteral ByteStringSeries => Expression.NewByteStringSeries(Sequence.Prepend($1, $2), @@)
    QuoteByteStringLiteral => Expression.NewQuoteByteString($1, @1)
    QuoteByteStringLiteral ByteStringSeries => Expression.NewQuoteByteStringSeries(Sequence.Prepend($1, $2), @@)

    Name => Expression.NewNameReference($1, @1)
    BuiltinTypeExpression => Expression.NewBuiltinTypeReference($1, @1)
    StackSlotValueReference => Expression.NewSlotValueReference($1, @1)
    StackSlotContextReference => Expression.NewSlotContextReference($1, @1)
    '$$' => Expression.NewResultValueReference(@1)
    '@@' => Expression.NewResultContextReference(@1)
    'this' => Expression.NewThisReference(@1)
    'base' => Expression.NewBaseReference(@1)
    '...' => Expression.NewEllipsis(@1)

    '(' ')' => Expression.NewUnit(@@)
    '[' ']' => Expression.NewEmptyList(@@)
    '{' '}' => Expression.NewEmptySet(@@)
    '{' ':' '}' => Expression.NewEmptyMap(@@)

    '(' YieldExpression ')' => Expression.NewGroup($2, @@)
    '(' TestExpression ')' => Expression.NewGroup($2, @@)

    '(' UnpackExpression ',' ')' => Expression.NewTuple(Sequence.Create($2), @@)
    '(' UnpackExpression ',' UnpackExpression %+ ',' ','? ')' => Expression.NewTuple(Sequence.Prepend($2, $4), @@)
    '(' FieldLabelValuePair %+ ',' ','? ')' => Expression.NewRecord($2, @@)
    'struct' '(' UnpackExpression %+ ',' ','? ')' => Expression.NewValueTuple($3, @@)
    'struct' '(' FieldLabelValuePair %+ ',' ','? ')' => Expression.NewValueRecord($3, @@)

    '[' UnpackExpression %+ ',' ','? ']' => Expression.NewList($2, @@)
    '{' UnpackExpression %+ ',' ','? '}' => Expression.NewSet($2, @@)
    '{' MapKeyValuePair %+ ',' ','? '}' => Expression.NewMap($2, @@)

    '(' TestExpression ComprehensionList ')' => Expression.NewGenerator($2, $3, @@)
    '[' TestExpression ComprehensionList ']' => Expression.NewListComprehension($2, $3, @@)
    '{' TestExpression ComprehensionList '}' => Expression.NewSetComprehension($2, $3, @@)
    '{' TestExpression ':' TestExpression ComprehensionList '}' => Expression.NewMapComprehension($2, $4, $5, @@)

PostfixExpression as Expression:
    PrimaryExpression => $1

    PostfixExpression '.' Name => Expression.NewAccess($1, $3, @@)
    PostfixExpression '?' '.' Name => Expression.NewNullableAccess($1, $4, @@)
    PostfixExpression ArgumentList => Expression.NewCall($1, $2, @@)
    PostfixExpression SubscriptList => Expression.NewSubscript($1, $2, @@)

    'new' TypeExpression ArgumentList => Expression.NewNew($2, $3, @@)
    'default' '(' TypeExpression ')' => Expression.NewDefault($3, @@)
    'typeof' '(' TypeExpression ')' => Expression.NewTypeOf($3, @@)
    'nameof' '(' BitwiseOrExpression ')' => Expression.NewNameOf($3, @@)

    PostfixExpression '++' => Expression.NewPostfixIncrement($1, @@)
    PostfixExpression '--' => Expression.NewPostfixDecrement($1, @@)

    PostfixExpression ':?' PrimaryTypeExpression => Expression.NewIsInstanceOf($1, $3, @@)
    PostfixExpression ':?>' PrimaryTypeExpression => Expression.NewAsInstanceOf($1, $3, @@)

    '[' ']' '!' => Expression.NewEmptyMutableList(@@)
    '{' '}' '!' => Expression.NewEmptyMutableSet(@@)
    '{' ':' '}' '!' => Expression.NewEmptyMutableMap(@@)

    '[' UnpackExpression %+ ',' ','? ']' '!' => Expression.NewMutableList($2, @@)
    '{' UnpackExpression %+ ',' ','? '}' '!' => Expression.NewMutableSet($2, @@)
    '{' MapKeyValuePair %+ ',' ','? '}' '!' => Expression.NewMutableMap($2, @@)

    '[' TestExpression ComprehensionList ']' '!' => Expression.NewMutableListComprehension($2, $3, @@)
    '{' TestExpression ComprehensionList '}' '!' => Expression.NewMutableSetComprehension($2, $3, @@)
    '{' TestExpression ':' TestExpression ComprehensionList '}' '!' => Expression.NewMutableMapComprehension($2, $4, $5, @@)

AwaitExpression as Expression:
    PostfixExpression => $1
    'await' PostfixExpression => Expression.NewAwait($2, @@)

PowerExpression as Expression:
    AwaitExpression => $1
    AwaitExpression '**' UnaryExpression => Expression.NewPower($1, $3, @@)

UnaryExpression as Expression:
    PowerExpression => $1
    '+' UnaryExpression => Expression.NewPositive($2, @@)
    '-' UnaryExpression => Expression.NewNegative($2, @@)
    '~' UnaryExpression => Expression.NewBitwiseNot($2, @@)
    '!' UnaryExpression => Expression.NewLogicalNot($2, @@)
    '++' UnaryExpression => Expression.NewPrefixIncrement($2, @@)
    '--' UnaryExpression => Expression.NewPrefixDecrement($2, @@)

MultiplicativeExpression as Expression:
    UnaryExpression => $1
    MultiplicativeExpression '*' UnaryExpression => Expression.NewMultiply($1, $3, @@)
    MultiplicativeExpression '@' UnaryExpression => Expression.NewMatrixMultiply($1, $3, @@)
    MultiplicativeExpression '//' UnaryExpression => Expression.NewFloorDivide($1, $3, @@)
    MultiplicativeExpression '/' UnaryExpression => Expression.NewDivide($1, $3, @@)
    MultiplicativeExpression '%' UnaryExpression => Expression.NewModulo($1, $3, @@)

AdditiveExpression as Expression:
    MultiplicativeExpression => $1
    AdditiveExpression '+' MultiplicativeExpression => Expression.NewAdd($1, $3, @@)
    AdditiveExpression '-' MultiplicativeExpression => Expression.NewSubtract($1, $3, @@)

ShiftExpression as Expression:
    AdditiveExpression => $1
    ShiftExpression '<<' AdditiveExpression => Expression.NewLeftShift($1, $3, @@)
    ShiftExpression '>>' AdditiveExpression => Expression.NewRightShift($1, $3, @@)
    ShiftExpression '>>>' AdditiveExpression => Expression.NewUnsignedRightShift($1, $3, @@)

BitwiseAndExpression as Expression:
    ShiftExpression => $1
    BitwiseAndExpression '&' ShiftExpression => Expression.NewBitwiseAnd($1, $3, @@)

BitwiseXorExpression as Expression:
    BitwiseAndExpression => $1
    BitwiseXorExpression '^' BitwiseAndExpression => Expression.NewBitwiseXor($1, $3, @@)

BitwiseOrExpression as Expression:
    BitwiseXorExpression => $1
    BitwiseOrExpression '|' BitwiseXorExpression => Expression.NewBitwiseOr($1, $3, @@)

RelationalOpValuePair as RelationalOpValuePair:
    '<' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.LessThan, $2, @@)
    '<=' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.LessEqual, $2, @@)
    '>' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.GreaterThan, $2, @@)
    '>=' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.GreaterEqual, $2, @@)
    '==' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.EqualTo, $2, @@)
    '!=' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.NotEqualTo, $2, @@)
    'is' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.Is, $2, @@)
    'is' 'not' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.IsNot, $3, @@)
    'in' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.In, $2, @@)
    'not' 'in' BitwiseOrExpression => RelationalOpValuePair.New(RelationalOp.NotIn, $3, @@)

RelationalExpression as Expression:
    BitwiseOrExpression => $1
    BitwiseOrExpression RelationalOpValuePair+ => Expression.NewRelational($1, $2, @@)
    
LogicalNotExpression as Expression:
    RelationalExpression => $1
    'not' LogicalNotExpression => Expression.NewLogicalNot($2, @@)

LogicalAndExpression as Expression:
    LogicalNotExpression => $1
    LogicalAndExpression 'and' LogicalNotExpression => Expression.NewLogicalAnd($1, $3, @@)
    LogicalAndExpression '&&' LogicalNotExpression => Expression.NewLogicalAnd($1, $3, @@)

LogicalOrExpression as Expression:
    LogicalAndExpression => $1
    LogicalOrExpression 'or' LogicalAndExpression => Expression.NewLogicalOr($1, $3, @@)
    LogicalOrExpression '||' LogicalAndExpression => Expression.NewLogicalOr($1, $3, @@)

TestExpression as Expression:
    LogicalOrExpression => $1
    LogicalOrExpression 'if' LogicalOrExpression 'else' TestExpression => Expression.NewConditional($3, $1, $5, @@)
    'lambda' LambdaParameterList ':' TestExpression => Expression.NewLambda($2, $4, @@)

TestExpressionList as Expression:
    TestExpression => $1
    TestExpression ',' => Expression.NewTuple(Sequence.Create($1), @@)
    TestExpression ',' TestExpression %+ ',' ','? => Expression.NewTuple(Sequence.Prepend($1, $3), @@)

YieldExpression as Expression:
    'yield' 'from' TestExpression => Expression.NewYieldFrom($3, @@)
    'yield' TestExpressionList => Expression.NewYield($2, @@)
    'yield' => Expression.NewYield(None, @@)
    'yield' 'break' => Expression.NewYieldBreak(@@)

FieldLabelValuePair as FieldLabelValuePair:
    Name '=' TestExpression => FieldLabelValuePair.New($1, $3, @@)

TargetExpression as Expression:
    BitwiseOrExpression => $1
    '*' BitwiseOrExpression => Expression.NewUnpack($2, @@)

TargetExpressionList as Expression:
    TargetExpression => $1
    TargetExpression ',' => Expression.NewTuple(Sequence.Create($1), @@)
    TargetExpression ',' TargetExpression %+ ',' ','? => Expression.NewTuple(Sequence.Prepend($1, $3), @@)

UnpackExpression as Expression:
    TestExpression => $1
    '*' BitwiseOrExpression => Expression.NewUnpack($2, @@)

UnpackExpressionList as Expression:
    UnpackExpression => $1
    UnpackExpression ',' => Expression.NewTuple(Sequence.Create($1), @@)
    UnpackExpression ',' UnpackExpression %+ ',' ','? => Expression.NewTuple(Sequence.Prepend($1, $3), @@)

MapKeyValuePair as MapKeyValuePair:
    TestExpression ':' TestExpression => MapKeyValuePair.New($1, $3, @@)
    '**' BitwiseOrExpression => MapKeyValuePair.New(None, $2, @@)
